#include "mqtt_helper.h"
#include "esp_log.h"
#include "esp_event.h"
#include "mqtt_client.h"
#define TAG "MQTT"

static esp_mqtt_client_handle_t client = NULL;

static mqtt_listener_t listener = NULL;

static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{
    switch (event->event_id)
    {
    case MQTT_EVENT_CONNECTED:
        ESP_LOGI(TAG, "Connected to MQTT broker");
        if (listener != NULL)
        {
            listener(MQTT_STATE_CONNECTED, 0);
        }
        break;
    case MQTT_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "Disconnected from MQTT broker");
        if (listener!=NULL)
        {
            listener(MQTT_STATE_DISCONNECTED,0);
        }
        if (client != NULL)
        {
            esp_mqtt_client_reconnect(client);
        }
        break;
    case MQTT_EVENT_DATA:
        // ESP_LOGI(TAG, "Received data: %.*s", event->data_len, event->data);
        if (listener!=NULL)
        {
            char *data = malloc(event->data_len + 1);
            memcpy(data, event->data, event->data_len);
            data[event->data_len] = '\0'; // Null-terminate the string

            mqtt_message_t msg;
            msg.state = MQTT_STATE_DATA;
            msg.topic = strndup(event->topic, event->topic_len);
            msg.payload = data;
            msg.qos = event->qos;
            msg.retain = event->retain;

            listener(MQTT_STATE_DATA,&msg);
            free(msg.topic);
            free(msg.payload);
        }
        break;
    default:
        break;
    }
    return ESP_OK;
}

static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    mqtt_event_handler_cb((esp_mqtt_event_handle_t)event_data);
}

void mqtt_start(char * uri, int port, char * clientId, char * userName, char * password, mqtt_listener_t mqtt_listener)
{
    if (listener != NULL)
    {
        return;
    }
    
    listener = mqtt_listener;
    esp_mqtt_client_config_t mqtt_cfg = {
        .broker.address.uri = uri,
        .broker.address.port = port,
        .credentials.client_id = clientId,
        .credentials.username = userName,
        .credentials.authentication.password = password,
    };

    client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
    esp_mqtt_client_start(client);
}

void mqtt_stop(void)
{
    if (client == NULL)
    {
        return;
    }
    esp_mqtt_client_stop(client);
}

void mqtt_disconnect(void)
{
    if (client == NULL)
    {
        return;
    }
    esp_mqtt_client_disconnect(client);
}

void mqtt_reconnect(void)
{
    if (client == NULL)
    {
        return;
    }
    esp_mqtt_client_reconnect(client);
}



int mqtt_subscribe_topic(const char* topic,int qos){
    return esp_mqtt_client_subscribe(client, topic, qos);
}

int mqtt_unsubscribe_topic(const  char* topic){
    return esp_mqtt_client_unsubscribe(client, topic);
}

int mqtt_publish_topic(const char* topic,const char* payload,int qos,int retain){
    return esp_mqtt_client_publish(client, topic, payload, strlen(payload), qos, retain);
}